﻿using System;
using System.Collections.Generic;
using System.Text;
using RS.DOM.Common;
using RS.DOM.Construction;

namespace RS.DOM.Types
{
    public class String: Token
    {
        public String(Context context, string res)
            : base(context)
        {
            base.TokenType = TokenType.String;
            base.Result = res;
        }

        public override Token Operation(Token token, OperationType type)
        {
            if (type == OperationType.Plus)
            {
                return this.Plus(token);
            }
            if (type == OperationType.PlusApply)
            {
                return this.PlusApply(token);
            }
            else if (type == OperationType.Generate)
            {
                return this.Generate(token);
            }
            else if (type == OperationType.Apply)
            {
                return this.Apply(token);
            }
            else if (type == OperationType.Equal)
            {
                return this.Equal(token);
            }
            else if (type == OperationType.Add)
            {
                return this.Add(token);
            }
            else
            {
                return base.Operation(token, type);
            }
        }

        public Token Add(Token token)
        {
            Collection result = null;

            if (token.TokenType == TokenType.String)
            {
                String op1 = this;
                String op2 = (String)token;

                result = new Collection(this.Context);

                result.Result.Add(op1);
                result.Result.Add(op2);
            }
            else if (token.TokenType == TokenType.Collection)
            {
                String op1 = this;
                Collection op2 = (Collection)token;

                result = new Collection(this.Context);

                result.Result.Add(op1);
                result.Result.AddRange(op2.Result);
            }

            return result;
        }


        public Token Apply(Token token)
        {
            String result = (String)this;

            if (token.TokenType == TokenType.String)
            {
                String op1 = this;
                String op2 = (String)token;

                op1.Result = op2.Result;
                result = op1;
            }

            return result;
        }

        public Token Equal(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.String)
            {
                String op1 = this;
                String op2 = (String)token;

                result = new Bool(this.Context, op1.Result == op2.Result);
            }

            return result;
        }


        public Token Generate(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.String)
            {
                string alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
                String op1 = this;
                String op2 = (String)token;
                Collection c = new Collection(this.Context);

                int idx1 = alphabet.IndexOf(op1.Result);
                int idx2 = alphabet.IndexOf(op2.Result);

                if (idx1 < idx2)
                {
                    for (int i = idx1; i <= idx2; i++)
                        c.Result.Add(new String(this.Context, alphabet[i].ToString()));
                }
                else
                {
                    for (int i = idx1; i >= idx2; i--)
                        c.Result.Add(new String(this.Context, alphabet[i].ToString())); 
                }

                result = c;
            }

            return result;
        }


        public override Token UnarOperation(OperationType type)
        {
            if (type == OperationType.Power)
            {
                Document doc = new Document(this.Result);
                doc.Build();
                return doc.Execute();
            }

            return this;
        }

        public Token Plus(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.String)
            {
                String op1 = this;
                String op2 = (String)token;
                result = new String(this.Context, op1.Result + op2.Result);
            }
            else if (token.TokenType == TokenType.Number)
            {
                String op1 = this;
                Number op2 = (Number)token;
                result = new String(this.Context, op1.Result + op2.Result.ToString());
            }
            
            return result;
        }

        public Token PlusApply(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.String)
            {
                String op1 = this;
                String op2 = (String)token;
                
                this.Result += op2.Result;
            }
            else if (token.TokenType == TokenType.Number)
            {
                String op1 = this;
                Number op2 = (Number)token;
                this.Result += op2.Result.ToString();
            }

            return result;
        }

        public string Result
        {
            get
            {
                return (string)base.Result;
            }

            set
            {
                base.Result = value;
            }
        }

        public override Token Create()
        {
            return new String(this.Context, this.Result);
        }

        public override string ToString()
        {
            return this.Result.ToString();
        }
    }
}
